package xyz.labmem.lipx.core.tool

import java.text.DecimalFormat
import java.util.concurrent.ExecutorService
import java.util.concurrent.Executors


class ConsoleProgressBar(
    private val barLen: Int,
    private val showChar: Char,
    private var label: String = "加载中",
    private var finished: ((ConsoleProgressBar) -> Unit)? = null
) {

    private var valueStep = 0

    private var valueSize = 0

    private var valueOne = 0.0

    private var loopSwitch: Boolean = true

    private val executor: ExecutorService = Executors.newSingleThreadExecutor()

    private val formater = DecimalFormat("#.##%")

    fun setValueSize(valueSize: Int) {
        if (valueSize > 0) {
            this.valueSize = valueSize
            valueOne = 100.0.div(valueSize)
        }
    }

    /**
     * 显示进度条
     */
    fun show(value: Double = -1.0) {
        if (value > 100) {
            finished?.let { it(this) }
            return
        }
        reset()
        if (value < 0) {
            Thread { drawLoop(barLen, 0, "$showChar".repeat(barLen / 3)) }.start()
        } else {
            // 比例
            val rate = (value * 1.0 / 100).toFloat()
            // 比例*进度条总长度=当前长度
            draw(barLen, rate)
            if (value.toLong() >= 100L) {
                afterComplete()
            }
        }
    }

    fun step() {
        executor.execute {
            valueStep++
            show(valueStep * valueOne)
            if (valueStep >= valueSize)
                finished?.let { it(this) }
        }
    }

    /**
     * 循环加载
     */
    private fun drawLoop(barLen: Int, p: Int, scs: String) {
        val sl = barLen / 3
        print("$label: ")
        if (barLen - p < sl) {
            print("$showChar".repeat(sl - (barLen - p)))
        }
        print(" ".repeat(if (barLen - p < sl) barLen - sl else p))
        if (barLen - p < sl) {
            print("$showChar".repeat(barLen - p))
        } else {
            print(scs)
            print(" ".repeat(barLen - p - sl))
        }
        print(" | " + if (p % 2 == 0) "/" else if (p % 3 == 0) "-" else if (p % 5 == 0) "+" else "\\")
        if (loopSwitch) {
            Thread.sleep(50)
            reset()
            if (barLen - p <= 0)
                drawLoop(barLen, 0, scs)
            else
                drawLoop(barLen, p + 1, scs)
        } else {
            afterComplete()
        }
    }

    /**
     * 画指定长度个showChar
     */
    private fun draw(barLen: Int, rate: Float) {
        val len = (rate * barLen).toInt()
        print("$label: ")
        for (i in 0 until len) {
            print(showChar)
        }
        for (i in 0 until barLen - len) {
            print(" ")
        }
        print(" |" + format(rate))
    }


    /**
     * 光标移动到行首
     */
    private fun reset() {
        print('\r')
    }

    /**
     * 完成后换行
     */
    private fun afterComplete() {
        print('\n')
    }

    private fun format(num: Float): String {
        return formater.format(num.toDouble())
    }

    fun stopLoop() {
        loopSwitch = false
        Thread.sleep(100)
    }

}